package net.bat.filter;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import net.bat.entity.Attach;

import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springside.modules.persistence.SearchFilter;
import org.springside.modules.persistence.SearchFilter.Operator;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;

public class ExtReq {
	public enum Oper {
		EQ, LIKE, GT, LT, GE, LE, IN
	}

	private static final SimpleDateFormat fmt_date = new SimpleDateFormat("MM/dd/yyyy");

	private ObjectMapper mapper = new ObjectMapper();

	public Map<String, SearchFilter> parseFilter(String filter) throws Exception {
		Map<String, SearchFilter> sfm = Maps.newHashMap();
		if (filter == null) {
			return sfm;
		}
		ExtJSFilter[] fliters = mapper.readValue(filter, ExtJSFilter[].class);
		for (ExtJSFilter ef : fliters) {
			String filedName = ef.getProperty();
			SearchFilter sf = new SearchFilter(filedName, Operator.valueOf(ef.getOperator().toUpperCase()),
					ef.getValue());
			sfm.put(filedName, sf);
		}
		return sfm;
	}

	public Sort parseSort(String sort) throws Exception {
		if (sort == null) {
			return null;
		}
		ExtJSSort[] sorts = mapper.readValue(sort, ExtJSSort[].class);
		Order[] os = new Order[sorts.length];
		int pos = 0;
		for (ExtJSSort es : sorts) {
			String filedName = es.getProperty();
			Order so = new Order(Direction.valueOf(es.getDirection().toUpperCase()), filedName);
			os[pos++] = so;
		}
		return new Sort(os);
	}

	public <T> JPAReq parse(String filter, String sort, Class<T> cls) throws Exception {
		JPAReq req = new JPAReq();
		if (filter != null) {
			StringBuffer sbuf = new StringBuffer();
			ExtJSFilter[] fliters = mapper.readValue(filter, ExtJSFilter[].class);
			List queryParams = new ArrayList();
			// Object[] queryParams = new Object[fliters.length + 1];
			for (ExtJSFilter ef : fliters) {
				String filedName = ef.getProperty();
				// 处理外键 many-to-many
				if ((ef.getExactMatch() != null) && ef.getExactMatch()) {
					// TODO add ename filter
					if (cls == Attach.class) {
						// articleId 拆分成两个条件ename和eid
						String ename = ef.getProperty().substring(0, ef.getProperty().length() - 2).toUpperCase();
						if (queryParams.size() == 0) {
							sbuf.append(" ename=(?1)");
						} else {
							sbuf.append(" and ename=(?" + queryParams.size() + 1 + ")");
						}
						queryParams.add(ename);

						filedName = "eid";
						ef.setOperator("eq");
					} else {
						filedName = "pid";
						ef.setOperator("eq");
					}
				}
				if (queryParams.size() == 0) {
					sbuf.append(" " + filedName);
				} else {
					sbuf.append(" and " + filedName);
				}
				Oper oper = Oper.valueOf(ef.getOperator().toUpperCase());
				Object val = ef.getValue();
				// EQ, LIKE, GT, LT, GTE, LTE
				String paraPos = "(?" + (queryParams.size() + 1) + ")";
				switch (oper) {
				case EQ:
					sbuf.append(" =" + paraPos);
					break;
				case LIKE:
					sbuf.append(" like " + paraPos);
					val = "%" + val + "%";
					break;
				case GT:
					sbuf.append(" >" + paraPos);
					break;
				case LT:
					sbuf.append(" <" + paraPos);
					break;
				case GE:
					sbuf.append(" >=" + paraPos);
					break;
				case LE:
					sbuf.append(" <=" + paraPos);
					break;
				case IN:
					sbuf.append(" in " + paraPos);
					queryParams.add(val);
					continue;
				}
				// 如果参数值与目标属性不匹配,需要特殊处理,例如：日期
				Field f = null;
				try {
					f = cls.getDeclaredField(filedName);
				} catch (Exception e) {
					// getDeclaredField 无法获得 extend的父类field
					f = cls.getSuperclass().getDeclaredField(filedName);
				}
				Class<?> fcl = f.getType();
				if ((val != null) && !fcl.isAssignableFrom(val.getClass())) {
					if (fcl.isAssignableFrom(Date.class)) {
						// val = fmt_date.parse(val.toString());
						// dateformat: time
						val = new Date(Long.parseLong(val.toString()));
					} else if (fcl.isAssignableFrom(Long.class)) {
						// 检索传值integer与期待值long不匹配
						val = Long.parseLong(val.toString());
					}
				}
				queryParams.add(val);
			}
			req.setWhereql(sbuf.toString());
			req.setQueryParams(queryParams.toArray());
		}
		if (sort != null) {
			LinkedHashMap<String, String> orderby = new LinkedHashMap<String, String>();
			ExtJSSort[] sorts = mapper.readValue(sort, ExtJSSort[].class);
			for (ExtJSSort es : sorts) {
				orderby.put(es.getProperty(), es.getDirection());
			}
			req.setOrderby(orderby);
		}
		return req;
	}
}
